﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Speech.Recognition;

namespace CodeTalk.CTSpeechCommands
{
    class PressKey : SpeechCommand
    {
        private List<KeyValuePair<string, string>> allKeys = null;

        private void CreateAllKeys()
        {
            if (allKeys == null)
            {
                allKeys = new List<KeyValuePair<string, string>>();
                allKeys.Add(new KeyValuePair<string, string>("Alpha", "a"));
                allKeys.Add(new KeyValuePair<string, string>("Bravo", "b"));
                allKeys.Add(new KeyValuePair<string, string>("Charlie", "c"));
                allKeys.Add(new KeyValuePair<string, string>("Delta", "d"));
                allKeys.Add(new KeyValuePair<string, string>("Echo", "e"));
                allKeys.Add(new KeyValuePair<string, string>("Foxtrot", "f"));
                allKeys.Add(new KeyValuePair<string, string>("Golf", "g"));
                allKeys.Add(new KeyValuePair<string, string>("Hotel", "h"));
                allKeys.Add(new KeyValuePair<string, string>("India", "i"));
                allKeys.Add(new KeyValuePair<string, string>("Juliet", "j"));
                allKeys.Add(new KeyValuePair<string, string>("Kilo", "k"));
                allKeys.Add(new KeyValuePair<string, string>("Lima", "l"));
                allKeys.Add(new KeyValuePair<string, string>("Mike", "m"));
                allKeys.Add(new KeyValuePair<string, string>("November", "n"));
                allKeys.Add(new KeyValuePair<string, string>("Oscar", "o"));
                allKeys.Add(new KeyValuePair<string, string>("Pappa", "p"));
                allKeys.Add(new KeyValuePair<string, string>("Quebec", "q"));
                allKeys.Add(new KeyValuePair<string, string>("Romeo", "r"));
                allKeys.Add(new KeyValuePair<string, string>("Sierra", "s"));
                allKeys.Add(new KeyValuePair<string, string>("Tango", "t"));
                allKeys.Add(new KeyValuePair<string, string>("Uniform", "u"));
                allKeys.Add(new KeyValuePair<string, string>("Victor", "v"));
                allKeys.Add(new KeyValuePair<string, string>("Whiskey", "w"));
                allKeys.Add(new KeyValuePair<string, string>("X-ray", "x"));
                allKeys.Add(new KeyValuePair<string, string>("Yankee", "y"));
                allKeys.Add(new KeyValuePair<string, string>("Zulu", "z"));

                allKeys.Add(new KeyValuePair<string, string>("Cap", "+"));
                allKeys.Add(new KeyValuePair<string, string>("Control", "^"));
                allKeys.Add(new KeyValuePair<string, string>("Alt", "%"));

                allKeys.Add(new KeyValuePair<string, string>("space", " "));
                allKeys.Add(new KeyValuePair<string, string>("space bar", " "));
                allKeys.Add(new KeyValuePair<string, string>("Enter", "{ENTER}"));
                allKeys.Add(new KeyValuePair<string, string>("Backspace", "{BKSP}"));
                allKeys.Add(new KeyValuePair<string, string>("Delete", "{DEL}"));
                allKeys.Add(new KeyValuePair<string, string>("End", "{END}"));
                allKeys.Add(new KeyValuePair<string, string>("Home", "{HOME}"));
                allKeys.Add(new KeyValuePair<string, string>("Tabulator", "{TAB}"));
                allKeys.Add(new KeyValuePair<string, string>("Page up", "{PGUP}"));
                allKeys.Add(new KeyValuePair<string, string>("Page down", "{PGDN}"));
                allKeys.Add(new KeyValuePair<string, string>("Escape", "{ESC}"));
                allKeys.Add(new KeyValuePair<string, string>("Arrow up", "{UP}"));
                allKeys.Add(new KeyValuePair<string, string>("Arrow down", "{DOWN}"));
                allKeys.Add(new KeyValuePair<string, string>("Arrow left", "{LEFT}"));
                allKeys.Add(new KeyValuePair<string, string>("Arrow right", "{RIGHT}"));
                allKeys.Add(new KeyValuePair<string, string>("F 1", "{F1}"));
                allKeys.Add(new KeyValuePair<string, string>("F 2", "{F2}"));
                allKeys.Add(new KeyValuePair<string, string>("F 3", "{F3}"));
                allKeys.Add(new KeyValuePair<string, string>("F 4", "{F4}"));
                allKeys.Add(new KeyValuePair<string, string>("F 5", "{F5}"));
                allKeys.Add(new KeyValuePair<string, string>("F 6", "{F6}"));
                allKeys.Add(new KeyValuePair<string, string>("F 7", "{F7}"));
                allKeys.Add(new KeyValuePair<string, string>("F 8", "{F8}"));
                allKeys.Add(new KeyValuePair<string, string>("F 9", "{F9}"));
                allKeys.Add(new KeyValuePair<string, string>("F 10", "{F10}"));
                allKeys.Add(new KeyValuePair<string, string>("F 11", "{F11}"));
                allKeys.Add(new KeyValuePair<string, string>("F 12", "{F12}"));

                allKeys.Add(new KeyValuePair<string, string>("1", "1"));
                allKeys.Add(new KeyValuePair<string, string>("2", "2"));
                allKeys.Add(new KeyValuePair<string, string>("3", "3"));
                allKeys.Add(new KeyValuePair<string, string>("4", "4"));
                allKeys.Add(new KeyValuePair<string, string>("5", "5"));
                allKeys.Add(new KeyValuePair<string, string>("6", "6"));
                allKeys.Add(new KeyValuePair<string, string>("7", "7"));
                allKeys.Add(new KeyValuePair<string, string>("8", "8"));
                allKeys.Add(new KeyValuePair<string, string>("9", "9"));
                allKeys.Add(new KeyValuePair<string, string>("0", "0"));

                allKeys.Add(new KeyValuePair<string, string>("Equals", "="));
                allKeys.Add(new KeyValuePair<string, string>("Open paren", "{(}"));
                allKeys.Add(new KeyValuePair<string, string>("Close paren", "{)}"));
                allKeys.Add(new KeyValuePair<string, string>("Open brace", "{{}"));
                allKeys.Add(new KeyValuePair<string, string>("Close brace", "{}}"));
                allKeys.Add(new KeyValuePair<string, string>("Open bracket", "{[}"));
                allKeys.Add(new KeyValuePair<string, string>("Close bracket", "{]}"));
                allKeys.Add(new KeyValuePair<string, string>("Less than", "<"));
                allKeys.Add(new KeyValuePair<string, string>("Greater than", ">"));
                allKeys.Add(new KeyValuePair<string, string>("Plus", "{+}"));
                allKeys.Add(new KeyValuePair<string, string>("Plus sign", "{+}"));
                allKeys.Add(new KeyValuePair<string, string>("Minus", "-"));
                allKeys.Add(new KeyValuePair<string, string>("Minus sign", "-"));
                allKeys.Add(new KeyValuePair<string, string>("Dash", "-"));
                allKeys.Add(new KeyValuePair<string, string>("Comma", ","));
                allKeys.Add(new KeyValuePair<string, string>("Dot", "."));
                allKeys.Add(new KeyValuePair<string, string>("Period", "."));
                allKeys.Add(new KeyValuePair<string, string>("Colon", ":"));
                allKeys.Add(new KeyValuePair<string, string>("Semi-colon", ";"));
                allKeys.Add(new KeyValuePair<string, string>("Exclamation mark", "!"));
                allKeys.Add(new KeyValuePair<string, string>("Question mark", "?"));
                allKeys.Add(new KeyValuePair<string, string>("Hash sign", "#"));
                allKeys.Add(new KeyValuePair<string, string>("Sharp", "#"));
                allKeys.Add(new KeyValuePair<string, string>("Slash", "/"));
                allKeys.Add(new KeyValuePair<string, string>("Backslash", "\\"));
                allKeys.Add(new KeyValuePair<string, string>("Star", "*"));
                allKeys.Add(new KeyValuePair<string, string>("Asterisk", "*"));
                allKeys.Add(new KeyValuePair<string, string>("Single quote", "'"));
                allKeys.Add(new KeyValuePair<string, string>("Quote", "\""));
                allKeys.Add(new KeyValuePair<string, string>("Underscore", "_"));
                allKeys.Add(new KeyValuePair<string, string>("Caret", "{^}"));
                allKeys.Add(new KeyValuePair<string, string>("Ampersand", "{&}"));
                allKeys.Add(new KeyValuePair<string, string>("And sign", "{&}"));
                allKeys.Add(new KeyValuePair<string, string>("Percent", "{%}"));
                allKeys.Add(new KeyValuePair<string, string>("Percent sign", "{%}"));
                allKeys.Add(new KeyValuePair<string, string>("Tilde", "{~}"));
                allKeys.Add(new KeyValuePair<string, string>("Pipeline", "|"));
                allKeys.Add(new KeyValuePair<string, string>("At sign", "@"));
            }
        }

        internal override GrammarBuilder GrammarBld(Context context, Context[] libraries)
        {
            CreateAllKeys();

            Choices c = new Choices();
            foreach (var kvp in allKeys)
                c.Add(kvp.Key);

            GrammarBuilder gb = new GrammarBuilder("press");
            gb.Append(c, 1, 32);
            return gb;
        }

        public override string Name
        {
            get { return "Press Key"; }
        }

        public override string Description
        {
            get { return Name; }
        }

        public override string GetAlternativesFeedback(string recognizedText, SemanticValue semValue)
        {
            if (recognizedText.StartsWith("press "))
            {
                string txt = recognizedText.Substring(6);

                return MatchKeys(allKeys, ref txt);
            }

            return "";
        }

        internal override bool CanSpokenFormMatch(string spokenForm)
        {
            spokenForm = spokenForm.ToLowerInvariant();
            if (spokenForm.StartsWith("press "))
            {
                string txt = spokenForm.Substring(6);

                foreach (var key in allKeys)
                {
                    if (txt.StartsWith(key.Key.ToLowerInvariant()))
                        return true;
                }
            }

            return false;
        }

        private string MatchKeys(List<KeyValuePair<string, string>> keys, ref string txt)
        {
            StringBuilder toPress = new StringBuilder();

            while (txt.Length > 0)
            {
                bool match = false;
                foreach (var key in keys)
                {
                    if (txt.StartsWith(key.Key))
                    {
                        toPress.Append(key.Value);
                        txt = txt.Substring(key.Key.Length);

                        while (txt.Length > 0 && txt[0] == ' ') txt = txt.Substring(1);
                        match = true;
                    }
                }
                if (!match) return toPress.ToString();
            }
            return toPress.ToString();
        }

        internal override object Execute(SpeechMode callingMode, string recognizedText, SemanticValue semValue)
        {
            if (recognizedText.StartsWith("press "))
            {
                string txt = recognizedText.Substring(6);

                string toPress = MatchKeys(allKeys, ref txt);

                callingMode.CurrentOutputHandler.SendKeys(toPress);
                callingMode.CurrentGuiHandler.SetPrimaryFeedback(toPress);

                return TextUtilz.GetUndoString(toPress);
            }
            return null;
        }
    }
}
